using System;
using System.Collections.Generic;
using System.Text;
using VisualizationPackage.FileLoader;

namespace VisualizationPackage
{
    public class Bezier
    {
        /*  Subroutine to generate a Bezier curve.
            Copyright (c) 2000 David F. Rogers. All rights reserved.
            
            b[]        = array containing the defining polygon vertices
                          b[1] contains the x-component of the vertex
                          b[2] contains the y-component of the vertex
                          b[3] contains the z-component of the vertex
            Basis      = function to calculate the Bernstein basis value (see MECG Eq 5-65)
            cpts       = number of points to be calculated on the curve
            Fractrl    = function to calculate the factorial of a number
            j[]        = array containing the basis functions for a single value of t
            npts       = number of defining polygon vertices
            p[]        = array containing the curve points
                         p[1] contains the x-component of the point
                         p[2] contains the y-component of the point
                         p[3] contains the z-component of the point
            t          = parameter value 0 <= t <= 1
        */

        /* function to calculate the factorial */
        static int ntop = 6;
        static float[] a = new float[33];// { 1.0f, 1.0f, 2.0f, 6.0f, 24.0f, 120.0f, 720.0f };

        public static float factrl(int n)
        {
            a[0] = 1.0f;
            a[1] = 1.0f;
            a[2] = 2.0f;
            a[3] = 6.0f;
            a[4] = 24.0f;
            a[5] = 120.0f;
            a[6] = 720.0f; /* fill in the first few values */
            int j1;

            if (n < 0 || n > 32)
                return -1;

            while (ntop < n)
            { /* use the precalulated value for n = 0....6 */
                j1 = ntop++;
                a[n] = a[j1] * ntop;
            }
            return a[n]; /* returns the value n! as a floating point number */
        }

        /* function to calculate the factorial function for Bernstein basis */

        private static float Ni(int n, int i)
        {
            float ni;
            ni = factrl(n) / (factrl(i) * factrl(n - i));
            return ni;
        }

        /* function to calculate the Bernstein basis */

        public static float Basis(int n, int i, float t)
        {
            float basis;
            float ti; /* this is t^i */
            float tni; /* this is (1 - t)^i */

            /* handle the special cases to avoid domain problem with pow */

            if (t == 0 && i == 0) ti = 1.0f; else ti = (float)Math.Pow(t, i);
            if (n == i && t == 1) tni = 1.0f; else tni = (float)Math.Pow((1 - t), (n - i));
            basis = Ni(n, i) * ti * tni; /* calculate Bernstein basis function */
            return basis;
        }

        /* Bezier curve subroutine */

        public static Vertex[] CalculateBezier(Vertex[] bOriginal, int outputCount)
        {
            Vertex[] pOutput = new Vertex[outputCount];
            int i;
            int i1;

            float step = 1.0f / (pOutput.Length - 1);
            float t = 0;

            for (i1 = 0; i1 < pOutput.Length; i1++)
            {
                if ((1.0 - t) < 5e-6)
                    t = 1.0f;

                pOutput[i1] = new Vertex();
                pOutput[i1].X = 0;
                pOutput[i1].Y = 0;
                pOutput[i1].Z = 0;
                for (i = 0; i < bOriginal.Length; i++)
                {
                    /* Do x, y, z components */
                    float basis = Basis(bOriginal.Length - 1, i, t);
                    pOutput[i1].X += basis * bOriginal[i].X;
                    pOutput[i1].Y += basis * bOriginal[i].Y;
                    pOutput[i1].Z += basis * bOriginal[i].Z;
                }
                t += step;
            }
            return pOutput;
        }
    }
}
